'''
获取邮件附件
'''
import os
import poplib
from email.parser import Parser
from email.header import Header, decode_header
from email.utils import parseaddr
import traceback

# 账户信息
email = 'my_email_liao@sina.com' # 你的邮箱
password = '05b359f59b2efd78' # 邮箱第三方密码
pop3_server = 'pop.sina.com' # pop3服务器地址
# 连接到POP3服务器，带SSL的:
server = poplib.POP3_SSL(pop3_server)
# 可以打开或关闭调试信息:
server.set_debuglevel(0)
# POP3服务器的欢迎文字:
print(server.getwelcome())
# 身份认证:
server.user(email)
server.pass_(password)
# stat()返回邮件数量和占用空间:
msg_count, msg_size = server.stat()
print(f'消息总数: {msg_count}')
print(f'消息占用空间: {msg_size} bytes')

def main(count):
    resp, byte_lines, octets = server.retr(count)
    # 转码
    str_lines = []
    for x in byte_lines:
        str_lines.append(x.decode())
    # 拼接邮件内容
    msg_content = '\n'.join(str_lines)
    # 把邮件内容解析为Message对象
    msg = Parser().parsestr(msg_content)
    headers = get_email_headers(msg)
    attachments = get_email_file(msg, 'email_file')
    # 输出
    print('subject:', headers['Subject'])
    print('from:', headers['From'])
    print('to:', headers['To'])
    if 'cc' in headers:
        print('cc:', headers['Cc'])
    print('date:', headers['Date'])
    print('attachments: ', attachments)
    print('-----------------------------')

def decode_str(s):
    '''进行消息解码'''
    value, charset = decode_header(s)[0]
    # decode_header()返回一个list，因为像Cc、Bcc这样的字段可能包含多个邮件地址，所以解析出来的会有多个元素。
    # 这里偷了个懒，只取了第一个元素。
    if charset:
        value = value.decode(charset)
    return value

def get_email_headers(msg):
    '''解析邮件头信息'''
    headers = {}
    for header in ['From', 'To', 'Cc', 'Subject', 'Date']:
        value = msg.get(header, '')
        if value:
            if header == 'Date':
                headers['Date'] = value
            if header == 'Subject':
                subject = decode_str(value) # 对主题进行解码
                headers['Subject'] = subject
            if header == 'From':
                hdr, addr = parseaddr(value) # 获取发件人和接收人的名称和邮箱地址
                name = decode_str(hdr)
                from_addr = u'%s <%s>' % (name, addr)
                headers['From'] = from_addr
            if header == 'To':
                all_cc = value.split(',')
                to = []
                for x in all_cc:
                    hdr, addr = parseaddr(x)
                    name = decode_str(hdr)
                    to_addr = u'%s <%s>' % (name, addr)
                    to.append(to_addr)
                headers['To'] = ','.join(to)
            if header == 'Cc':
                all_cc = value.split(',')
                cc = []
                for x in all_cc:
                    hdr, addr = parseaddr(x)
                    name = decode_str(hdr)
                    cc_addr = u'%s <%s>' % (name, addr)
                    cc.append(cc_addr)
                headers['Cc'] = ','.join(cc)
    return headers

def get_email_file(message, savepath):
    '''下载附件'''
    attachments = []
    for part in message.walk(): # 遍历邮件体中所有的段
        filename = part.get_filename()
        try:
            if filename:
                filename = decode_str(filename)
                data = part.get_payload(decode=True)
                 # 文件夹不存在，则创建
                if not os.path.exists(savepath):
                    os.makedirs(savepath)
                abs_filename = os.path.join(savepath, filename)
                with open(abs_filename, 'wb') as f:
                    f.write(data) # 下载附件
                attachments.append(filename)
                print('下载完成')
        except:
            traceback.print_exc() # 打印完整错误栈
    return attachments


if __name__ == '__main__':
    main(msg_count)